﻿#define _CRT_SECURE_NO_WARNINGS
#include "Snake.h"
//改变光标位置
void setpos(int x, int y)
{
	HANDLE outhandle = GetStdHandle(STD_OUTPUT_HANDLE);
	COORD pos = { x,y };
	SetConsoleCursorPosition(outhandle, pos);
}
void print_wall()
{
	int i = 0;
	for (i = 0; i < 29; i++)
	{
		wprintf(L"%lc", wall);
	}
	setpos(0, 26);
	for (i = 0; i < 29; i++)
	{
		wprintf(L"%lc", wall);
	}
	for (i = 1; i <= 25; i++)
	{
		setpos(0, i);
		wprintf(L"%lc", wall);
	}
	for (i = 1; i <= 25; i++)
	{
		setpos(56, i);
		wprintf(L"%lc", wall);
	}
}
void show()
{
	setpos(35, 12);
	wprintf(L"欢迎来到贪吃蛇小游戏");
	setpos(38, 25);
	system("pause");
	system("cls");
	setpos(15, 12);
	wprintf(L"用 ↑ . ↓ . ← . → 分别控制蛇的移动， F3为加速，F4为减速");
	setpos(35, 13);
	wprintf(L"加速将能得到更高的分数。");
	setpos(38, 25);
	system("pause");
	system("cls");
	//打印墙体
	print_wall();
}
//初始化蛇身
void Inint_snake(pSnake ps)
{
	for (int i = start; i <= 32; i+=2)
	{
		PSnaekNode pcur = (PSnaekNode)malloc(sizeof(SnakeNode));
		if (pcur == NULL)
		{
			perror("pcur malloc");
			return;
		}
		pcur->next = NULL;
		pcur->x = i;
		pcur->y = 5;
		if (ps->_Snake == NULL)
		{
			ps->_Snake = pcur;
		}
		else
		{
			pcur->next = ps->_Snake;
			ps->_Snake = pcur;
		}
		pcur = ps->_Snake;
		while (pcur)
		{
			setpos(pcur->x, pcur->y);
			wprintf(L"%lc", snakebody);
			pcur = pcur->next;
		}
		ps->_food_weight = 10;
		ps->_SnakeDeriction = RIGHT;
		ps->_Statue = OK;
		ps->_sleeptime = 200;//毫秒
		ps->_score = 0;
	}
}
void Createfood(pSnake ps)
{
	//记录食物坐标
	int x = 0;
	int y = 0;	
	again:
	do
	{
		x = (rand() % 53) + 2;
		y = (rand() % 25) + 1;
	} while (x % 2 != 0);//保证食物的坐标可以被蛇给吃掉
	//判断食物是否与蛇身重合
	PSnaekNode cur = ps->_Snake;
	while (cur)
	{
		if (cur->x == x && cur->y ==y)
		{
			goto again;
		}
		cur = cur->next;
	}
	//申请一个食物节点
	ps->_pfood =(PSnaekNode)malloc(sizeof(SnakeNode));
	if (ps->_pfood == NULL)
	{
		perror("pfood");
		return;
	}
	ps->_pfood->x = x;
	ps->_pfood->y = y;
	ps->_pfood->next = NULL;
	setpos(x,y);
	wprintf(L"%lc", food);
}
void GameBegin(pSnake ps)
{
	//设置窗口大小
	system("mode con cols=100 lines=50");
	system("title 植物大战僵尸");
	//隐藏光标
HANDLE outhandle =	GetStdHandle(STD_OUTPUT_HANDLE);
CONSOLE_CURSOR_INFO console_cursor_info;
GetConsoleCursorInfo(outhandle, &console_cursor_info);
console_cursor_info.bVisible = false;
SetConsoleCursorInfo(outhandle, &console_cursor_info);
//打印初始界面
show();
//初始化蛇
 Inint_snake(ps);
 //创建打印食物
 Createfood(ps);
}
//打印帮助信息
void print_helpinfo()
{
	setpos(64, 15);
	wprintf(L"不能穿墙，不能咬到自己");
	setpos(64, 16);
	wprintf(L"用↑.↓.←.→分别控制蛇的移动.");
	setpos(64, 17);
	wprintf(L"F3 为加速，F4 为减速");
	setpos(64, 18);
	wprintf(L"ESC ：退出游戏.space：暂停游戏.");
	setpos(64, 19);
	wprintf(L"小曹制作");
}
void gamepause()
{
	while (1)
	{
		Sleep(1);
		if (keycheck(VK_SPACE))
		{
			break;
		}
	}
}
//如果是吃食物并释放掉下一个节点
void EatFood(PSnaekNode pnext, pSnake ps)
{
	ps->_pfood->next = ps->_Snake;
	ps->_Snake = ps->_pfood;
	free(pnext);
	pnext = NULL;
	//再次打印蛇身
	PSnaekNode cur = ps->_Snake;
	while (cur)
	{
		setpos(cur->x, cur->y);
		wprintf(L"%lc", snakebody);
		cur = cur->next;
	}
	ps->_score += ps->_food_weight;
	//下面在创建一个食物
	Createfood(ps);
}
//如果不是先把下一个节点挂上在释放掉最后一个节点
void NoFood(PSnaekNode pnext, pSnake ps)
{
	pnext->next = ps->_Snake;
	ps->_Snake = pnext;

	PSnaekNode pcur = ps->_Snake;
	PSnaekNode prev = ps->_Snake;
	while (pcur->next)
	{
		setpos(pcur->x, pcur->y);
		wprintf(L"%lc", snakebody);
		prev = pcur;
		pcur = pcur->next;
	}
	setpos(pcur->x, pcur->y);
	printf("  ");
	free(pcur);
	prev->next = NULL;
}
//判断下一个节点是不是食物
int check_pnext(PSnaekNode pnext, pSnake ps)
{
	return (pnext->x == ps->_pfood->x)&& (pnext->y == ps->_pfood->y);
}
//蛇的移动
void snakemove(pSnake ps)
{
	PSnaekNode pnext = (PSnaekNode)malloc(sizeof(SnakeNode));
	if (pnext == NULL)
	{
		perror("pnext");
		return;
	}
	switch (ps->_SnakeDeriction)
	{
	case UP:
		pnext->x = ps->_Snake->x;
		pnext->y = ps->_Snake->y - 1;
		break;
	case DOWN:
		pnext->x = ps->_Snake->x;
		pnext->y = ps->_Snake->y + 1;
		break;
	case LEFT:
		pnext->x = ps->_Snake->x-2;
		pnext->y = ps->_Snake->y;
		break;
	case RIGHT:
		pnext->x = ps->_Snake->x + 2;
		pnext->y = ps->_Snake->y;
		break;
	}
	//这里判断下一个节点是不是食物的位置
	if (check_pnext(pnext, ps))
	{
		//如果是吃食物并释放掉下一个节点
		EatFood(pnext, ps);
		pnext = NULL;
	}
	else
	{
		//如果不是先把下一个节点挂上在释放掉最后一个节点
		NoFood(pnext, ps);
	}
}
//检查是否撞到墙体和自身
void killbywall(pSnake ps)
{
	if (ps->_Snake->x == 56 || ps->_Snake->x == 0 || ps->_Snake->y == 0 || 
		ps->_Snake->y == 26)
	{
		ps->_Statue = KILL_BY_WALL;
	}
}
void killbyself(pSnake  ps)
{
	PSnaekNode pcur = ps->_Snake->next;
	while (pcur)
	{
		if (pcur->x == ps->_Snake->x && pcur->y == ps->_Snake->y)
		{
			ps->_Statue = KILL_BY_SEIF;
			break;
		}
		pcur = pcur->next;
	}
}
//进行按键检测
void Check_Key(pSnake ps)
{
	do
	{
		setpos(64, 10);
		printf("食物分数：%2d", ps->_food_weight);
		setpos(64, 11);
		printf("总得分：%d", ps->_score);
		if (keycheck(VK_UP)&&ps->_SnakeDeriction!=DOWN)
		{
			ps->_SnakeDeriction = UP;
		}
		else if (keycheck(VK_DOWN)&&ps->_SnakeDeriction!=UP)
		{
			ps->_SnakeDeriction = DOWN;
		}
		else if (keycheck(VK_LEFT)&&ps->_SnakeDeriction!=RIGHT)
		{
			ps->_SnakeDeriction = LEFT;
		}
		else if (keycheck(VK_RIGHT)&&ps->_SnakeDeriction!=LEFT)
		{
			ps->_SnakeDeriction = RIGHT;
		}
		else if (keycheck(VK_SPACE))
		{
			//暂停
			gamepause();
		}
		else if (keycheck(VK_ESCAPE))
		{
			//退出
			ps->_Statue = END_NORMAL;
		}
		else if (keycheck(VK_F3))
		{
			//加速
			if (ps->_sleeptime > 80)
			{
				ps->_sleeptime -= 30;
				ps->_food_weight += 2;
			}
		}
		else if (keycheck(VK_F4))
		{
			//减速
			if (ps->_food_weight > 2)
			{
				ps->_sleeptime += 30;
				ps->_food_weight -= 2;
			}
		}
		snakemove(ps);
		Sleep(ps->_sleeptime);
		killbywall(ps);
		killbyself(ps);
	} while (ps->_Statue == OK);
}
//4.结束游戏
void Gameend(pSnake ps)
{
	setpos(24, 13);
	switch (ps->_Statue)
	{
	case END_NORMAL:
		printf("您主动结束游戏");
		break;
	case KILL_BY_SEIF:
		printf("您撞到自己游戏结束");
		break;
	case KILL_BY_WALL:
		printf("您撞到墙游戏结束");
		break;
	}
	//进行链表的释放
	PSnaekNode pcur = ps->_Snake;
	while (pcur)
	{
		PSnaekNode pnext = pcur->next;
		free(pcur);
		pcur = pnext;
	}
}
//3.运行游戏
void Gamerun(pSnake ps)
{
	//打印帮助信息
	print_helpinfo();
	//进行按键检测并进行移动
	Check_Key(ps);
	
}